Met de R-library leaflet kunnen interactieven kaarten gemaakt worden. Deze kaarten kunnen opgenomen worden in quarto documenten. In dit hoofdstuk zullen enkele veelgebruikte toepassingen beschreven worden. De uitleg zal niet ingaan op alle mogelijkheden van leaflet. Lees daarvoor zelf de documentatie van leaflet en deze Rstudio pagina over leaflet.
Basis leafletkaart
Met de functie leaflet() kunnen we een lege leafletkaart aanroepen. In de meeste gevallen willen we een basiskaart als achtergrond hebben. Dit kan met de functie addTiles(). De onderstaande code maakt een leaflet object met de standaard wereldkaart als achtergrond. Zie: Standaard achtergrondkaart aanpassen
library(dplyr)
Attaching package: 'dplyr'
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
library(leaflet)leaflet() %>%addTiles()
Leaflet en digitoegankelijkheid
Het is mogelijk om digitoegankelijke kaarten met Leaflet te maken. Kaartlagen kunnen alt-text krijgen die door een screenreader wordt voorgelezen. Helaas gaat dit niet vanzelf wanneer je de leaflet library van R gebruikt. Om dit issue op te lossen kunnen we een hulpfunctie gebruiken die alt-text toevoegt aan een leafletkaart. Zie de onderstaande tip om de functie add_alt_text te kopieren. De functie werkt voor polygonen, markers en cirkels.
Kopieer hier de javascript-functie voor alt-text
# functie om dmv JavaScript aria-label aan markers, polygons en cirkels toe te voegen# obv labelsadd_alt_text <-function(map) { js_code <-" function(el, x) { // Loop langs elke laag van map en voeg alt-text toe o.b.v label this.eachLayer(function(layer) { // Voor Markers if(layer instanceof L.Marker) { var altText = layer.getTooltip() ? layer.getTooltip().getContent() : ''; if(altText) { layer._icon.setAttribute('aria-label', altText); layer._icon.setAttribute('role', 'img'); } } // Voor Polygonen if(layer instanceof L.Polygon) { var altText = layer.getTooltip() ? layer.getTooltip().getContent() : ''; if(altText) { layer.getElement().setAttribute('aria-label', altText); layer.getElement().setAttribute('role', 'img'); } } // Voor cirkels if(layer instanceof L.Circle) { var altText = layer.getTooltip() ? layer.getTooltip().getContent() : ''; if(altText) { layer.getElement().setAttribute('aria-label', altText); layer.getElement().setAttribute('role', 'img'); } } }); } " map <- map %>% htmlwidgets::onRender(jsCode = js_code) map}
De alt-text functie werkt voor polygonen en markers en kan je als volgt aanroepen:
leaflet() %>%addTiles() %>%addMarkers(...) %>%addPolygons(...) %>%add_alt_text() #Voegt alt text toe o.b.v. de labels voor markers en polygonen
Net als met alle andere tools is het belangrijk dat je zelf goed nadenkt over digitoegankelijkheid. De labels die je toevoegt aan je polygonen of markers moeten informatief zijn. Als je kaart puur decoratief is zou je die uit kunnen zetten voor screen readers. Dat wordt hier niet uitgelegd. Zie voor meer informatie: A guide to basic leaflet accessibility.
Kleurvlakken (Choropleth)
Informatie over gebieden zoals gemeenten, wijken of postcodegebieden tonen op de kaart kan met een Choropleth. Dat is een kaart met kleurvlakken. Hieronder wordt uitgelegd hoe we dat in R kunnen doen met leaflet.
Polygonen toevoegen aan kaart
Om een Choropleth te maken moeten we polygonen toevoegen aan de kaart. Polygonen zijn 2D oppervlakken die in dit geval gebieden op de kaart vertegenwoordigen.
CBS Shapefiles downloaden
CBS shapefiles kan kan je hier downloaden als ingepakt .gpkg bestand per jaar.
Ieder .gpkg bestand bevat meerdere lagen met shapefiles. Deze kunnen we met de functie st_layers() uit de library sf opvragen:
library(sf)#Haal een overzicht van de beschikbare lagen in het .gpkg bestand op shapekaarten_cbs <-st_layers("shapefiles/cbsgebiedsindelingen2024.gpkg")#Voorbeeld van uitvoer: laat de laatste 6 laagnamen zienshapekaarten_cbs$name %>%tail()
Om polygonen met data toe te voegen aan een leaflet kaart hebben we een bestand met polygonen nodig. We gebruiken de functie st_read() library sf om zulke bestanden te lezen. In dit voorbeeld wordt een shapefile uit een .gpkg bestand van het CBS gebruikt. Zie de tip hierboven om die data zelf op te halen. Andere geo-bestandstypen zijn ook in te lezen met st_read().
SF-dataframes
De functie st_read() maakt sf-dataframes. Deze objecten werken op dezelfde manier als reguliere dataframes en kunnen dus ook zo bevraagd en bewerkt worden. Dit maakt data toevoegen of ophalen uit sf-dataframes intuitief.
test =st_read("provincies.shp") #een shapefile inlezentest$nieuw =1#nieuwe variabele toewijzenprint(test$statnaam) #alle namen van provincies printen> [1] "Groningen""Fryslân""Drenthe""Overijssel""Flevoland""Gelderland""Utrecht"> [8] "Noord-Holland""Zuid-Holland""Zeeland""Noord-Brabant""Limburg"
Hieronder wordt een shapefile met polygonen van Nederlandse provincies ingelezen en toegevoegd aan een leafletkaart. Omdat leaflet een ander CRS gebruikt dan de shapefiles moet dit eerst omgezet worden met st_transform()
Polygonen worden toegevoegd met de functie addPolygons.
#shapefile inlezen uit gpkg layersf_provincie <-st_read("shapefiles/cbsgebiedsindelingen2024.gpkg",layer ="provincie_gegeneraliseerd",quiet =TRUE) %>%st_transform(4326) #CRS aanpassen naar leaflet standaard#leafletkaart maken met polygonenleaflet(data = sf_provincie) %>%addTiles() %>%addPolygons(label =~statnaam, #label = naam provinciecolor ="black",weight =1) %>%#lijnen polygoon zijn zwart & dikte 1add_alt_text() #alt-text toevoegen
Data koppelen aan sf-dataframe
Om de polygonen in te kleuren o.b.v. verschillende waarden per provincie moeten we data aan het sf-dataframe toevoegen. Hieronder wordt fictieve data per provincie gemaakt en gekoppeld aan het sf-dataframe d.m.v. de dplyr functie left_join().
#Alle provinciecodes uit sf-dataframe halenprovinciecodes = sf_provincie$statcode#fictieve data genererendf_fictief <-data.frame("statcode"= provinciecodes,"rapportcijfer"=sample(x =1:10,size =length(provinciecodes),replace =TRUE) #willekeurig getal tussen 1 en 10 genereren )#data koppelen aan sf_provincie dmv dplyr::left_joinsf_provincie = sf_provincie %>%left_join(df_fictief, by ="statcode")
Nu er inhoudelijke data is toegevoegd aan het sf-dataframe kan de data weergeven worden op de leafletkaart. Hier zijn verschillende mogelijkheden voor:
Polygonen inkleuren: Continue kleurovergang o.b.v. numerieke data
Met de leaflet functie colorNumeric() kan een continue kleurschaal gedefinieerd worden. Die kan hierna toegevoegd worden aan de functies addPolygons() en addLegend() om de kaart in te kleuren en een legenda toe te voegen.
Paletten in R
In het onderstaande voorbeeld wordt voor colorNumeric() palette=“YlOrRd” opgegeven. Dit is de naam van een standaard palet uit RcolorBrewer. Voer de onderstaande code uit om een overzicht te krijgen van alle standaard paletten uit RcolorBrewer.
RColorBrewer::display.brewer.all()
Een andere veelgebruikte library is viridis (heel handig voor heatmaps)
Je kan ook je eigen kleurenpaletten maken met de functie colorRampPalette(). Dit is erg handig er hele specifieke wensen zijn voor de kleuren op je leafletkaart.
#maak kleurenfunctie voor een continue kleurschaal o.b.v. de fictieve datapal =colorNumeric(palette ="YlOrRd", domain = df_fictief$rapportcijfer)#leafletkaart makenleaflet(data = sf_provincie) %>%addTiles() %>%addPolygons(fillColor =~pal(rapportcijfer), #kleuren o.b.v. rapportcijferlabel =~statnaam, #label = naam provincie)color ="black",weight =1) %>%#lijnen polygoon zijn zwart & dikte = 1addLegend(pal = pal,values =~rapportcijfer, position ="bottomright"#legenda o.b.v. rapportcijfer positie rechtsonder ) %>%add_alt_text() #alt-text toevoegen
Polygonen inkleuren: Categorische kleurovergang o.b.v numerieke data
Als je kleuren per categorie wilt toewijzen kan dat op een vergelijkbare manier. In plaats van colorNumeric() gebruiken we alleen met de functie colorBin() en wijzen we de gewenste categorieën toe door aan het argumnet bins door een vector te maken die alle categorieën vangt.
Warning
Als je drie categorieën wilt maken moet je een vector van 5 cijfers opgeven! De ‘bins’ of categorieën vallen tussen twee waarden. De laagste categorie in het voorbeeld bevat dus alle cijfers tussen 0 en 5.
#maak kleurenfunctie voor een categorische kleurschaal o.b.v. de fictieve datapal =colorBin(palette ="YlOrRd",domain = df_fictief$rapportcijfer,bins =c(0,5,7,10) )#leafletkaart makenleaflet(data = sf_provincie) %>%addTiles() %>%addPolygons(fillColor =~pal(rapportcijfer), #kleuren o.b.v. rapportcijferlabel =~statnaam, #label = naam provincie)color ="black",weight =1) %>%#lijnen polygoon zijn zwart & dikte = 1addLegend(pal = pal,values =~rapportcijfer,position ="bottomright" ) %>%add_alt_text() #alt-text toevoegen
Polygonen inkleuren: Zelf categorieën inkleuren
Het is ook mogelijk om handmatig kleuren en labels te kiezen. Dit kan om de kleuren direct aan het sf-dataframe toe te voegen en te gebruiken in addPolygons(). Vervolgens kunnen we in AddLegend() de argumenten colors & labels gebruiken om ‘handmatig’ een legenda op te bouwen.
#kleuren als variabele aan sf-dataframe toevoegen o.b.v. rapportcijferssf_provincie <- sf_provincie %>%mutate(kleur =case_when( rapportcijfer <5~"red", #Alles onder 5 is rood rapportcijfer <7.5~"yellow", #Al het andere onder 7.5 is geelTRUE~"green"#Al het andere is groen ) )leaflet(data = sf_provincie) %>%addTiles() %>%addPolygons(fillColor =~kleur, #variabele kleur toewijzen aan fillColorlabel =~statnaam, #label = naam provinciecolor ="black",weight =1) %>%#lijnen polygoon zijn zwart & dikte = 1#legenda om de kleuren toe te lichtenaddLegend(colors =c("red","yellow","green"), #vector kleurenlabels =c("Onvoldoende","Voldoende","Goed") #vector labels ) %>%add_alt_text() #alt-text toevoegen
Punten met data toevoegen
Om informatie over specifieke locaties te tonen op de kaart kunnen we markers of circles toevoegen. Hiervoor hebben we een dataset nodig met punt-coordinaten. In dit voorbeeld zal er gebruik gemaakt worden van data van het RIVM over ‘natte koeltorens’ die is gedownload als ‘ESRI Shapefile’. Deze data is beschikbaar op het nationaal georegister.
Markers
Eerst wordt de data ingelezen als dataframe en wordt de CRS omgezet voor leaflet. Vervolgens wordt de shapefile op een leafletkaart geplot met de functie addMarkers(). Om te zorgen dat iedere ‘marker’ herkenbaar is wordt een label aangemaakt door de variabele ‘bedrijfsna’ & ‘beschrijvi’ aan elkaar te plakken.
Aangepaste icoontjes
Zie dit artikel en de functie addAwesomeMarkers() om markers toe te voegen waarvan je zelf het icoon en de kleur bepaald.
sf_koeltorens <-st_read("shapefiles/koeltorens/koeltoren_geaccepteerdPoint.shp",quiet =TRUE) %>%st_transform(4326) %>%mutate(label_toren =paste(bedrijfsna, beschrijvi) %>%iconv(to ="UTF-8"))#iconv() is in dit specifieke geval nodig omdat er tekens in de data zitten die niet UTF-8 zijn#leaflet kan daar niet mee werken.leaflet(sf_koeltorens) %>%addTiles() %>%addMarkers(label =~label_toren) %>%add_alt_text() #alt-text toevoegen
Cirkels
De data kan ook weergeven worden met Cirkels door de functie addCircles(). De kleur en de radius van die Cirkels kunnen ook bepaald worden de variabele ‘risico_cat’. De kleuren kunnen op dezelfde manier als hiervoor bepaald worden. In het voorbeeld is er voor de functie colorBin() gekozen.
Lagen die aan leaflet toegevoegd kunnen worden kunnen voorzien worden van een ‘popup’. Dit is een raampje met informatie dat tevoorschijn komt zodra de gebruiker op een element klikt. Bijvoorbeeld op een marker van een koeltoren, of op de polygoon van een provincie.
Leaflet popups kunnen worden opgemaakt met html en kunnen van alles bevatten, zelfs de leafletkaart zelf (niet aan te bevelen). Een simpel voorbeeld zou zijn om de naam van de provincie en het rapportcijfer in de popup te zetten.
glue
In onderstaand voorbeeld wordt de functie glue() gebruikt. glue() lijkt op de basisfunctie paste() maar werkt op een aantal punten anders. Hieronder wordt glue() gebruikt omdat de auteur dat leesbaarder en makkelijker te typen vindt dan paste(). vergelijk bijvoorbeeld paste() en glue() en oordeel zelf:
paste("Het rapportcijfer voor provincie",provincie_id, "is", rapportcijfer,". De provincie scoorde een",score_afsprong,"voor de afsprong")glue("Het rapportcijfer voor provincie {provincie_id} is {rapportcijfer}. De provincie scoorde een {score_afsprong} voor de afsprong")
Omdat de popups gevuld kunnen worden met HTML is het mogelijk complexere inhoud in te voegen. Wat bijvoorbeeld mogelijk is, om tabellen toe te voegen met de onderliggende scores voor fictieve rapportcijfers. In onderstaand voorbeeld wordt de fictieve dataset uitgebreid en worden er gt-tabellen gemaakt die in de popups worden gevoegd.
library(gt)#Fictieve data aanvullen met meer verzinselsdf_fictief <- df_fictief %>%mutate(sfeer =sample(1:10, size =n(), replace =TRUE),infrastructuur =sample(1:10, size =n(), replace =TRUE),afsprong =sample(1:10, size =n(), replace =TRUE),rapportcijfer = (sfeer + infrastructuur + afsprong) /3 )#provincie shapefile lezen en fictieve data koppelensf_provincie <-st_read("shapefiles/cbsgebiedsindelingen2024.gpkg",layer ="provincie_gegeneraliseerd",quiet =TRUE) %>%st_transform(4326) %>%#CRS aanpassen naar leaflet standaardleft_join(df_fictief, by ="statcode")#lijst met complexere popups maken incl gt tabellen#lapply: doe voor voor iedere 'statcode' x het onderstaande#en sla de uitvoer op in de lijstvariabele gt_popup in het sf-dataframesf_provincie$gt_popup <-lapply(unique(sf_provincie$statcode), function(x){ df_popup = sf_provincie %>%st_drop_geometry() %>%#van sf-dataframe naar regulier dataframefilter(statcode == x) #data filteren op provincie tabel_popup <- df_popup %>%select(sfeer, infrastructuur,afsprong) %>%gt() %>%as_raw_html()#voeg de tabel onder de een header en het rapportcijferglue("<h1>{df_popup$statnaam}</h1> <p>Rapportcijfer: {round(df_popup$rapportcijfer,1)}</p> {tabel_popup}") })leaflet(sf_provincie) %>%addTiles() %>%addPolygons(popup =~gt_popup) %>%add_alt_text() #alt-text toevoegen
Meer lagen per kaart en besturing voor kaartlagen
Meer kaartlagen
Om een leafletkaart met meer kaartlagen te maken kunnen simpelweg meerdere kaartlaagfuncties toegevoegd worden. Hieronder worden de polygpnen en circles uit eerdere voorbeelden beide toegevoegd.
Warning
In eerdere voorbeelden werden de sf-dataframes in het data argument van de functie leaflet() aangeroepen. Dit is geschikt voor kaarten waarbij er slechts 1 sf-dataframe is waar we gebruik van maken in de kaart.
Als er geodata uit meerdere databronnen komt kunnen de sf-dataframes aangeroepen in het data argument van leaflet-functie waar ze bij horen.
#palet voor cirkels watertorenspal_koeltorens =colorBin("YlOrRd",domain = sf_koeltorens$risico_cat, bins =4)#palet voor polygonen provinciespal_provincies =colorBin(palette ="Blues",domain = df_fictief$rapportcijfer,bins =c(0,5,7,10) )leaflet() %>%addTiles() %>%#polygonen sf_provincie toevoegen met fictieve dataaddPolygons(data = sf_provincie, #data bij kaartelement ingevoerd ipv leaflet()fillColor =~pal(rapportcijfer),label =~statnaam, color ="black",weight =1) %>%addCircles(data = sf_koeltorens, #data bij kaartelement ingevoerd ipv leaflet()label =~label_toren,radius =~risico_cat *100,fillColor =~pal(risico_cat),color =~pal(risico_cat)) %>%add_alt_text() #alt-text toevoegen
Besturing kaartlagen
Een kaart met meerdere lagen kan snel verwarrend worden. De kaartlagen kunnen voorzien worden van besturing. Er worden dan knoppen toegevoegd aan de kaart, waarmee een gebruiker de verschillende lagen aan of uit kan zetten. Dit kan gedaan worden met de functie AddLayersControl(). In het onderstaande voorbeeld wordt een knop toegevoegd voor beide kaartlagen.
Om te zorgen dat leaflet weet welke lagen aansproken moeten worden met de knoppen moet het argument ‘group’ ingevuld worden met een naam voor de group. Het is mogelijk om meerdere lagen aan één groep toe te wijzen door bij group dezelfde naam in te vullen.
In de functie AddLayersControl() moeten vervolgens de groepen benoemd worden in een character vector. We kunnen hiervoor de argumenten overlayGroups of baseGroups gebruiken. Het kan ook beide.
overlayGroups: Maakt ‘checkbox’ knoppen. Dit maakt het mogelijk om meerdere lagen tegelijk aan te zetten. Of om alle lagen uit te zetten.
baseGroups: Maakt ‘radio’ knoppen. Er kan dan slechts één groep geselecteerd worden en er staat altijd ten minste één groep aan.
In het onderstaande voorbeeld wordt overlayGroups gebruikt.
Verder wordt er een optie toegevoegd die ervoor zorgt dat de knoppen direct zichtbaar zijn d.m.v. options = layersControlOptions(collapsed = FALSE). Dit overschrijft de standaardinstelling waarbij de knoppen in een hamburgermenu worden gestopt.
Besturing voor andere kaartelementen
Er kunnen besturingselementen toegevoegd worden voor vrijwel alle leaflet functies. Bijvoorbeeld voor kaartachtergronden zoals uitgelegd in deze post: R-gallery Control Widget
Wanneer er data is toegevoegd aan een kaart zal een leafletkaart standaard openen met een orientatie en zoom waarbij de toegevoegde data zichtbaar is. Dit is meestal de bedoeling. Als dat niet zo is kunnen de zoom en de orientatie van de kaart ingesteld worden met setView(). De argumenten lng en lat worden gebruikt om de coordinaten van het midden van de ‘view’ door te geven. Het argument zoom bepaald hoe ver de kaart standaard is ingezoomd. Let op; hoe hoger de waarde, hoe verder ingezoomd.
leaflet() %>%addTiles() %>%setView(lng =5.332707,lat =51.67845, #Coordinaten van GGD HvB kantoor den Boschzoom =15)
Standaard achtergrondkaart aanpassen
Met de functie addTiles() voegen we een standaard achtergrondkaart of toe. De functie addProviderTiles() maakt het mogelijk om andere achtergrondkaarten toe te voegen.
Je kan de Leaflet Provider Demo raadplegen om verschillende voorbeelden te bekijken.
Als de library leaflet is geladen is ook standaard de lijst ‘providers’ ingelezen waardoor we gemakkelijk ‘provider tiles’ kunnen selecteren. Door ‘providers$’ te typen verschijnt er vanzelf een lijst met opties de opties.